package nfwx.analytics;

import java.util.Date;

/**
 * 视频信息采集会话
 */

public class GrabVideoSession extends GrabSession {
    //最大时间戳
    public final GrabNumber maxTime;
    //最大时间码
    public final GrabNumber maxTC;
    //播放器信息
    public final GrabPlayerInfo player;
    //视频元信息
    public final GrabVideoMeta meta;

    ///加载事件
    GrabVideoCommonEvent _loadEvent;
    ///seek事件
    GrabVideoCommonEvent _seekEvent;
    ///重新缓冲事件
    GrabVideoCommonEvent _rebufferEvent;

    ///当前流是否无信号
    boolean _noSignal;

    GrabVideoSession()
    {
        super(SESSION_TYPE_VIDEO);
        maxTime = (GrabNumber)defineProperty("maxTime", new GrabNumber(false));
        maxTC = (GrabNumber)defineProperty("maxTC", new GrabNumber(false));
        meta = (GrabVideoMeta)defineProperty("meta", new GrabVideoMeta());
        player = (GrabPlayerInfo)defineProperty("player", new GrabPlayerInfo());
        _loadEvent = new GrabVideoCommonEvent(GrabVideoEvent.EVENT_NAME_LOAD);
    }

    @Override
    void endSession()
    {
        super.endSession();
        submitPendingEvents();
    }

    /**
     * 提交未完成的事件
     */
    private void submitPendingEvents()
    {
        boolean end=getEnded();
        if (_loadEvent != null) { //还在加载中?
            _loadEvent.fin.setValue(false);
            if (end) {
                _loadEvent.exit.setValue(true);
            }
            double t = (new Date()).getTime();
            _loadEvent.loadTime.setValue(t - _loadEvent.time.getValue());
            if (_noSignal) {
                _loadEvent.noSignal.setValue(true);
            }
            this.events.push(_loadEvent);
            _loadEvent = null;
        }

        if (_seekEvent != null) { //还在seek中?
            _seekEvent.fin.setValue(false);
            if (end) {
                _seekEvent.exit.setValue(true);
            }
            double t = (new Date()).getTime();
            _seekEvent.loadTime.setValue(t - _seekEvent.time.getValue());
            if (_noSignal) {
                _seekEvent.noSignal.setValue(true);
            }
            this.events.push(_seekEvent);
            _seekEvent = null;
        }

        if (_rebufferEvent != null) { //还在buffer中?
            _rebufferEvent.fin.setValue(false);
            if (end) {
                _rebufferEvent.exit.setValue(true);
            }
            double t = (new Date()).getTime();
            _rebufferEvent.loadTime.setValue(t - _rebufferEvent.time.getValue());
            if (_noSignal) {
                _rebufferEvent.noSignal.setValue(true);
            }
            this.events.push(_rebufferEvent);
            _rebufferEvent = null;
        }
    }

    /**
     * 增加播放时间, 应用应当定时调用此函数用以累计使用时长
     * @param ms 增加的毫秒时长
     */
    public void increaseUseTime(long ms)
    {
        double v = ms;
        v += useTimeDelta.getValue();
        useTimeDelta.setValue(v);
    }

    /**
     * 加载完成
     * @param time 播放时间戳
     * @param tc 播放时间码
     * @param status 播放器状态
     */
    public void finishLoad(long time, long tc, String status)
    {
        if (_loadEvent == null) return;
        _loadEvent.fin.setValue(true);
        double t = (new Date()).getTime();
        _loadEvent.loadTime.setValue(t - _loadEvent.time.getValue());
        if (_noSignal) {
            _loadEvent.noSignal.setValue(true);
        }
        _loadEvent.playTime.setValue(time);
        _loadEvent.tc.setValue(tc);
        if (status != null) {
            _loadEvent.status.setValue(status);
        }
        this.events.push(_loadEvent);
        _loadEvent = null;
    }

    /**
     * 加载失败
     * @param errcode 错误码
     * @param msg 错误信息
     * @param status 播放器状态值
     */
    public void errorLoad(String errcode, String msg, String status)
    {
        if (_loadEvent == null) return;
        _loadEvent.fin.setValue(false);
        double t = (new Date()).getTime();
        _loadEvent.loadTime.setValue(t - _loadEvent.time.getValue());
        _loadEvent.errcode.setValue(errcode);
        _loadEvent.msg.setValue(msg);
        _loadEvent.status.setValue(status);
        if (_noSignal) {
            _loadEvent.noSignal.setValue(true);
        }
        this.events.push(_loadEvent);
        _loadEvent = null;
    }

    /**
     * 汇报当前播放时间信息
     * @param time 播放时间戳
     * @param tc 播放时间码
     */
    public void reportTimeInfo(long time, long tc)
    {
        if (getEnded()) return;
        if (!maxTime.getHasValue()) {
            maxTime.setValue(time);
        } else if (maxTime.getValue() < time) {
            maxTime.setValue(time);
        }
        if (!maxTC.getHasValue()) {
            maxTC.setValue(tc);
        } else if (maxTC.getValue() < tc) {
            maxTC.setValue(tc);
        }
    }

    /**
     * 报告无信号
     * @param v 是否无信号
     */
    public void reportNoSignal(boolean v)
    {
        _noSignal = v;
    }

    /**
     * 执行一次Seek
     * @param time 目标时间戳
     * @param tc 目标时间码
     */
    public void beginSeek(long time, long tc)
    {
        if (getEnded()) return;
        submitPendingEvents();
        reportTimeInfo(time, tc);
        _seekEvent = new GrabVideoCommonEvent(GrabVideoEvent.EVENT_NAME_SEEK);
        _seekEvent.playTime.setValue(time);
        _seekEvent.tc.setValue(tc);
    }

    /**
     * Seek完成
     */
    public void endSeek()
    {
        if (_seekEvent == null) return;
        _seekEvent.fin.setValue(true);
        double t = (new Date()).getTime();
        _seekEvent.loadTime.setValue(t - _seekEvent.time.getValue());
        if (_noSignal) {
            _seekEvent.noSignal.setValue(true);
        }
        this.events.push(_seekEvent);
        _seekEvent = null;
    }

    /**
     * 播放过程中开始缓冲
     * @param time 目标时间戳
     * @param tc 目标时间码
     * @param status 视频播放器状态信息
     */
    public void beginRebuffer(long time, long tc, String status)
    {
        if (getEnded()) return;
        if (_rebufferEvent == null) {
            submitPendingEvents();
        }
        reportTimeInfo(time, tc);
        if (_rebufferEvent == null) _rebufferEvent = new GrabVideoCommonEvent(GrabVideoEvent.EVENT_NAME_BUFFER);
        _rebufferEvent.playTime.setValue(time);
        _rebufferEvent.tc.setValue(tc);
        if (status != null) {
            _rebufferEvent.status.setValue(status);
        }
    }

    /**
     * Rebuffer完成
     */
    public void endRebuffer()
    {
        if (_rebufferEvent == null) return;
        _rebufferEvent.fin.setValue(true);
        double t = (new Date()).getTime();
        _rebufferEvent.loadTime.setValue(t - _rebufferEvent.time.getValue());
        if (_noSignal) {
            _rebufferEvent.noSignal.setValue(true);
        }
        this.events.push(_rebufferEvent);
        _rebufferEvent = null;
    }

    /**
     * 暂停事件
     * @param time 目标时间戳
     * @param tc 目标时间码
     */
    public void pauseEvent(long time, long tc)
    {
        if (getEnded()) return;
        submitPendingEvents();
        reportTimeInfo(time, tc);
        GrabVideoEvent e= new GrabVideoEvent(GrabVideoEvent.EVENT_NAME_PAUSE);
        e.playTime.setValue(time);
        e.tc.setValue(tc);
        events.push(e);
    }

    /**
     * 恢复事件
     * @param time 目标时间戳
     * @param tc 目标时间码
     */
    public void resumeEvent(long time, long tc)
    {
        if (getEnded()) return;
        submitPendingEvents();
        reportTimeInfo(time, tc);
        GrabVideoEvent e= new GrabVideoEvent(GrabVideoEvent.EVENT_NAME_RESUME);
        e.playTime.setValue(time);
        e.tc.setValue(tc);
        events.push(e);
    }

    /**
     * 播放完成事件
     * @param time 目标时间戳
     * @param tc 目标时间码
     */
    public void playEndEvent(long time, long tc)
    {
        if (getEnded()) return;
        submitPendingEvents();
        reportTimeInfo(time, tc);
        GrabVideoEvent e= new GrabVideoEvent(GrabVideoEvent.EVENT_NAME_END);
        e.playTime.setValue(time);
        e.tc.setValue(tc);
        events.push(e);
    }

    /**
     * 播放过程中错误事件
     * @param time 目标时间戳
     * @param tc 目标时间码
     */
    public void playErrEvent(long time, long tc, String errcode, String msg, String status)
    {
        if (getEnded()) return;
        submitPendingEvents();
        GrabVideoPlayErrEvent e= new GrabVideoPlayErrEvent();
        reportTimeInfo(time, tc);
        e.playTime.setValue(time);
        e.tc.setValue(tc);
        if (errcode != null) {
            e.errcode.setValue(errcode);
        }
        if (msg != null) {
            e.msg.setValue(msg);
        }
        if (status != null) {
            e.status.setValue(status);
        }
        events.push(e);
    }
}
